`timescale 1ps / 1ps
module alu (input [3:0]ALUctr,
            input [31:0]A,
            input [31:0]B,
            input [4:0]shf,
            input ALUshf,
            output reg [31:0]result,
            output reg OF,           //overflow flag
            output reg [31:0]Zero
            );

reg signed [31:0] sA;
reg signed [31:0] sB;
reg signed [31:0] sR;

reg neg_over;
reg pos_over;

initial begin
    OF   = 0;
    Zero = 0;
end

always @(*) begin
    sA = A;
    sB = B;
    case (ALUctr)
        0: result = sA + sB; //add
        1: result = A + B;   //addu
        2: result = sA - sB; //sub
        3: result = A - B;   //subu
        4: result = A & B;   //and
        5: result = A | B;   //or
        6: result = sA < sB ? 1 : 0;//slt
        7: result = A < B ? 1 : 0; //sltu
        8: result = ~ (A | B); //nor
        9: result = A ^ B; //xor
        10:result = B << A;//SLLV
        11:result = B >> A;//SRLV
        12:result = {B[15:0],16'd0};//LUI
        13:begin
            if (B[31] == 0)
                result = B >> A;
            else
                result = ~((~B)>>A);
        end //SRAV
    endcase

    if(ALUshf) begin
        if(ALUctr == 0) result = B << shf; //SLL
        if(ALUctr == 1) result = B >> shf; //SRL
        if(ALUctr == 2)begin
            if(B[31] == 0) result = B >> shf;
            else result = ~((~B)>>shf);
        end// SRA
    end
        
    Zero = (result == 0);
    sR   = result;
    
    case (ALUctr)
        0: begin
            sR       = sA + sB;
            neg_over = sA < 0 && sB < 0 && sR >= 0;
            pos_over = sA >= 0 && sB >= 0 && sR < 0;
            OF       = neg_over | pos_over;
        end
        1: begin
            OF = A[31] & B[31];
        end
        2: begin
            sR       = sA - sB;
            neg_over = sA < 0 && sB > 0 && sR >= 0;
            pos_over = sA >= 0 && sB <= 0 && sR < 0;
            OF       = neg_over | pos_over;
        end
        3: begin
            OF = A < B;
        end
        default: OF = 0;
    endcase
    Zero = result;
end

endmodule // alu